function [values2, varargout] = make_integers(values, varargin)
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	% This function takes some numerical values and converts them into integers.
	% If the input values are not integers, they will be converted to integers (by rounding).
	% The idea of this function is to encode integers efficiently, to use as little memory as possible.
	% This is particularly useful when storing vectors of indexes.
	%
	% The second arguments is the bounds (lower bound, upper bound) of possible values that could be encountered, so that
	% the integer type can be chosen adequately. If it is not passed, then the bounds are computed based on
	% the minimum and maximum of the values passed.
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%%%%% Inputs:
	% values:		array
	% varargin{1}:	[lwBound, upBound]
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%%%%% Outputs:
	% values2:		array of same dimension (but of some integer type)
	% varargout{1}: string representing integer type
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	% Get lower bound and upper bound
	if length(varargin) >= 1
		bounds = varargin{1};
		lwBound = bounds(1);
		upBound = bounds(2);
		if lwBound > upBound; error('Lower bound is greater than upper bound'); end;
		if min(values(:)) < lwBound; error('Lower bound is greater than minimum value.'); end;
		if max(values(:)) > upBound; error('Upper bound is lower than maximum value.'); end;
	else
		lwBound = min(values(:));
		upBound = max(values(:));
	end
	

	% Initialize flag and go through all possible cases
	conversionDone = false;
	
	% Case: 0 <= x <= 2^8-1:   convert to uint8
	if ~conversionDone && lwBound >= 0 && upBound <= 2^8-1
		values2 = uint8(values);
		conversionDone = true;
	end

	% Case: 0 <= x <= 2^16-1:   convert to uint16
	if ~conversionDone && lwBound >= 0 && upBound <= 2^16-1
		values2 = uint16(values);
		conversionDone = true;
	end

	% Case: 0 <= x <= 2^32-1:   convert to uint32
	if ~conversionDone && lwBound >= 0 && upBound <= 2^32-1
		values2 = uint32(values);
		conversionDone = true;
	end

	% Case: 0 <= x <= 2^64-1:   convert to uint64
	if ~conversionDone && lwBound >= 0 && upBound <= 2^64-1
		values2 = uint64(values);
		conversionDone = true;
	end

	% Case: -2^7 <= x <= 2^7-1:   convert to int8
	if ~conversionDone && lwBound >= -2^7 && upBound <= 2^7-1
		values2 = int8(values);
		conversionDone = true;
	end

	% Case: -2^15 <= x <= 2^15-1:   convert to int16
	if ~conversionDone && lwBound >= -2^15 && upBound <= 2^15-1
		values2 = int16(values);
		conversionDone = true;
	end

	% Case: -2^31 <= x <= 2^31-1:   convert to int32
	if ~conversionDone && lwBound >= -2^31 && upBound <= 2^31-1
		values2 = int32(values);
		conversionDone = true;
	end

	% Case: -2^63 <= x <= 2^63-1:   convert to int64
	if ~conversionDone && lwBound >= -2^63 && upBound <= 2^63-1
		values2 = int64(values);
		conversionDone = true;
	end
	
	% Cas where it is impossible to convert to integer: throw error
	if ~conversionDone
		values2 = values;
		disp('Values are too large to be converted to integer types!');
	end
	
	% Output new type if requested
	if nargout >= 2
		varargout{1} = class(values2);
	end
end
